package com.itmake.webflux.security.config;

import cn.hutool.core.util.ArrayUtil;
import com.itmake.webflux.security.handle.AccessFailHandler;
import com.itmake.webflux.security.handle.AuthFailHandler;
import com.itmake.webflux.security.service.IFluxUserDetailsService;
import com.itmake.webflux.security.filter.JwtFilter;
import com.itmake.webflux.security.property.SecurityProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.Objects;

/**
 * spring security 配置
 *
 * @author Amjacks
 * @since 2023/08/10
 */
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Autowired(required = false)
    private IFluxUserDetailsService fluxUserDetailsService;

    @Autowired
    private AuthFailHandler authFailHandler;

    @Autowired
    private AccessFailHandler accessFailHandler;

    @Autowired
    private SecurityProperty securityProperty;

    @Autowired
    private JwtFilter jwtFilter;

    /**
     * anyRequest          |   匹配所有请求路径
     * permitAll           |   用户可以任意访问
     * authenticated       |   用户登录后可访问
     */
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity) {
        httpSecurity
            // 基于 token，禁用 CSRF
            .csrf().disable()
            // 处理器
            .exceptionHandling()
                // 认证失败处理
                .authenticationEntryPoint(authFailHandler)
                // 鉴权失败处理
                .accessDeniedHandler(accessFailHandler).and()
            // 禁用自带的登录登出
            .logout().disable().formLogin().disable();
        // 开启认证
        if (securityProperty.getEnable().equals(Boolean.TRUE)) {
            // 白名单
            String[] white = ArrayUtil.toArray(securityProperty.getWhites(), String.class);
            httpSecurity.authorizeExchange(authorize -> authorize
                .pathMatchers(white).permitAll() // 白名单放行
                .anyExchange().authenticated() // 其他请求都需要认证
            );
        }
        // 用户登录实现
        if (Objects.nonNull(fluxUserDetailsService)) {
            httpSecurity.authenticationManager(
                    new UserDetailsRepositoryReactiveAuthenticationManager(fluxUserDetailsService));
        }
        // Jwt 过滤器
        httpSecurity.securityContextRepository(jwtFilter);
        // 构建
        return httpSecurity.build();
    }

    /**
     * 配置跨源 CORS
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }

    /**
     * 获取 ReactiveAuthenticationManager 认证管理器，用于登录的认证
     */
    @Bean
    public ReactiveAuthenticationManager authenticationManager() {
        UserDetailsRepositoryReactiveAuthenticationManager manager = new UserDetailsRepositoryReactiveAuthenticationManager(fluxUserDetailsService);
        manager.setPasswordEncoder(passwordEncoder());
        return manager;
    }

    /**
     * 密码明文加密方式配置
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
